Implement Utils.sort_tuples! for user-defined sorting

Akinori MUSHA 9 years ago
parent
commit
06554eaf31
2 changed files with 80 additions and 0 deletions
  1. 40 0
      lib/utils.rb
  2. 40 0
      spec/lib/utils_spec.rb

+ 40 - 0
lib/utils.rb

@@ -79,4 +79,44 @@ module Utils
79 79
   def self.pretty_jsonify(thing)
80 80
     JSON.pretty_generate(thing).gsub('</', '<\/')
81 81
   end
82
+
83
+  class TupleSorter
84
+    class SortableTuple
85
+      attr_reader :array
86
+
87
+      # The <=> method will call orders[n] to determine if the nth element
88
+      # should be compared in descending order.
89
+      def initialize(array, orders = [])
90
+        @array = array
91
+        @orders = orders
92
+      end
93
+
94
+      def <=> other
95
+        other = other.array
96
+        @array.each_with_index do |e, i|
97
+          case cmp = e <=> other[i]
98
+          when nil
99
+            return nil
100
+          when 0
101
+            next
102
+          else
103
+            return @orders[i] ? -cmp : cmp
104
+          end
105
+        end
106
+        0
107
+      end
108
+    end
109
+
110
+    class << self
111
+      def sort!(array, orders = [])
112
+        array.sort_by! do |e|
113
+          SortableTuple.new(e, orders)
114
+        end
115
+      end
116
+    end
117
+  end
118
+
119
+  def self.sort_tuples!(array, orders = [])
120
+    TupleSorter.sort!(array, orders)
121
+  end
82 122
 end

+ 40 - 0
spec/lib/utils_spec.rb

@@ -114,4 +114,44 @@ describe Utils do
114 114
       expect(cleaned_json).to include("<\\/script>")
115 115
     end
116 116
   end
117
+
118
+  describe "#sort_tuples!" do
119
+    let(:tuples) {
120
+      time = Time.now
121
+      [
122
+        [2, "a", time - 1],  # 0
123
+        [2, "b", time - 1],  # 1
124
+        [1, "b", time - 1],  # 2
125
+        [1, "b", time],      # 3
126
+        [1, "a", time],      # 4
127
+        [2, "a", time + 1],  # 5
128
+        [2, "a", time],      # 6
129
+      ]
130
+    }
131
+
132
+    it "sorts tuples like arrays by default" do
133
+      expected = tuples.values_at(4, 2, 3, 0, 6, 5, 1)
134
+
135
+      Utils.sort_tuples!(tuples)
136
+      expect(tuples).to eq expected
137
+    end
138
+
139
+    it "sorts tuples in order specified: case 1" do
140
+      # order by x1 asc, x2 desc, c3 asc
141
+      orders = [false, true, false]
142
+      expected = tuples.values_at(2, 3, 4, 1, 0, 6, 5)
143
+
144
+      Utils.sort_tuples!(tuples, orders)
145
+      expect(tuples).to eq expected
146
+    end
147
+
148
+    it "sorts tuples in order specified: case 2" do
149
+      # order by x1 desc, x2 asc, c3 desc
150
+      orders = [true, false, true]
151
+      expected = tuples.values_at(5, 6, 0, 1, 4, 3, 2)
152
+
153
+      Utils.sort_tuples!(tuples, orders)
154
+      expect(tuples).to eq expected
155
+    end
156
+  end
117 157
 end